#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoFaceSet.h>

#include "heightfield.hpp"
#include "notifiers.hpp"
#include "dexel.hpp"

#include <iostream>

using namespace std;



simplefacetter::simplefacetter(heightfield *m){
    result=new SoSeparator;
    result->ref();
    model=m;
  }
  
void simplefacetter::facet(facet_note *tic)
  {
    SoCoordinate3 *coords=new SoCoordinate3;
    SoFaceSet *faces=new SoFaceSet;

    long vert=0;
    long tri=0;
    
    for(long iy=0; iy<model->ny-1; iy++)
      for(long ix=0; ix<model->nx-1; ix++)
	{
	  point 
	    p1(model->unrefx(ix  ),model->unrefy(iy  ),
	       model->f[model->hand(ix  ,iy  )]),
	    p2(model->unrefx(ix+1),model->unrefy(iy  ),
	       model->f[model->hand(ix+1,iy  )]),
	    p3(model->unrefx(ix  ),model->unrefy(iy+1),
	       model->f[model->hand(ix  ,iy+1)]),
	    p4(model->unrefx(ix+1),model->unrefy(iy+1),
	       model->f[model->hand(ix+1,iy+1)]);

	  coords->point.set1Value(vert++,p1);
	  coords->point.set1Value(vert++,p2);
	  coords->point.set1Value(vert++,p3);
	  
	  coords->point.set1Value(vert++,p2);
	  coords->point.set1Value(vert++,p4);
	  coords->point.set1Value(vert++,p3);
    
	  faces->numVertices.set1Value(tri++,3);
	  faces->numVertices.set1Value(tri++,3);
	}
    result->removeAllChildren();
    result->addChild(coords);
    result->addChild(faces);
    
  }
  
SoSeparator* simplefacetter::Result()
  {
    return result;
  }
  

heightfield::heightfield():facet(this)
{
  dx=0;dy=0;
  xmin=0;
  xmax=0;
  ymin=0;  
  ymax=0;
  zmin=0;
  zmax=0;
    nx=0;
    ny=0;

    f=NULL;
          
}

heightfield::~heightfield()
{
  delete[] f;
}


heightfield::heightfield(double _xmin, double _ymin,
		       long _nx, long _ny,
			 double _dx, double _dy):facet(this)//,f(_nx*_ny)

{  
  dx=_dx;
  dy=_dy;
  xmin=_xmin;
  ymin=_ymin;

  zmax=-1000;
  zmin=1000;
  
  nx=_nx;
  ny=_ny;
  
  xmax=xmin+nx*dx;
  ymax=ymin+ny*dy;

  f=NULL;
  
}

void heightfield::blank(double xmin, double xmax,
		       double ymin, double ymax,
		       double _zmin, double _zmax,
		       double dx, double dy ){
  
  long mx=(xmax-xmin)/dx+3;
  long my=(ymax-ymin)/dy+3;

  *this=heightfield(xmin,ymin,mx,my,dx,dy);

  zmin=_zmin;
  zmax=_zmax;

  cerr<<"nx:"<<nx<<" ny:"<<ny<<endl;
  
  
  f=new double[(nx+5)*(ny+5)];

  for(int i=0; i<nx*ny; i++)
    f[i]=zmax;
  

  for(long i=0; i<nx; i++)
    f[hand(i,0)]=f[hand(i,ny-1)]=0;
  for(long i=0; i<ny; i++)
    f[hand(0,i)]=f[hand(nx-1,i)]=0;

  facet.model=this;
  
  
   
}

long heightfield::hand(long ix,long iy) const
{
  return iy*nx+ix;
}

long heightfield::referx(double x) const
{
  return (long)round((x-xmin)/dx);
}

long heightfield::refery(double y) const
{
  return (long)round((y-ymin)/dy);
}

double heightfield::unrefx(long ix) const
{
  return double(ix)*dx+xmin;
}

double heightfield::unrefy(long iy) const
{
  return double(iy)*dy+ymin;
}

long heightfield::dhand(double x, double y) const
{
  return hand(referx(x),refery(y));
}


void heightfield::apply_cutter(cutter *c)
{
  if(c->xmin()>=xmax || c->xmax()<=xmin ||
     c->ymin()>=ymax || c->ymax()<=ymin)
    return;
  
  
  double x_min=(xmin>c->xmin())?xmin:c->xmin();
  double x_max=(xmax<c->xmax())?xmax:c->xmax();

  double y_min=(ymin>c->ymin())?ymin:c->ymin();
  double y_max=(ymax<c->ymax())?ymax:c->ymax();

  double pc=0;
  int percents=0;
  double pp=
    (referx(x_max)-referx(x_min))*
    (refery(y_max)-refery(y_min));
  
  
  for(long ix=referx(x_min); ix<=referx(x_max); ix++)
    for(long iy=refery(y_min); iy<=refery(y_max); iy++)
      {
	interval cut=c->intersect_z(unrefx(ix),unrefy(iy));

	size_t has=hand(ix,iy);
	
	if(has<nx*ny && cut.e> cut.b && cut.b<f[has])
	    f[has]=cut.b;
	

	pc++;
	 
		 
      }
    
}

	
